/*************************************************************************
 *                                                                       *
 * This file is part of the FreeMAPs distribution.  For full copyright   *
 * information, see COPYRIGHT and COPYING.LESSER.                        *
 *                                                                       *
 * Author:           sqbang                                              *
 * Email:            sqbang@ustc.edu                                     *
 * Date:             2011.08.22                                          *
 *                                                                       *
 *************************************************************************/

#ifndef FreeMAPs_include_COMMON_bdry_IrregularBoundaryConditionStrategy_h
#define FreeMAPs_include_COMMON_bdry_IrregularBoundaryConditionStrategy_h

#include "FreeMAPsConfig.h"

//SAMRAI headers
#ifdef FREEMAPS_HAVE_SAMRAI
#  include "SAMRAI/pdat/CellData.h"
#endif

//LIBMESH headers

//COMMON headers
#include "COMMON/base/StateIndicator.h"
#include "COMMON/bdry/IrregularBoundaryConditionRange.h"
#include "COMMON/enum/BoundaryConditionType.h"
#include "COMMON/enum/DirectionType.h"

//#include "info/ParaFluxBean.h"


namespace FreeMAPs
{

//forward declarations
#ifdef FREEMAPS_HAVE_SAMRAI
class AttributeOfCell;
class StructuredDofMap;
#endif
class PDEEquationEnsembleStrategy;

/**
 * IrregularBoundaryConditionStrategy is a pure virtual class,
 * it derived class used in impose boundary conditions.
 * now three type of boundary conditions are supported:
 *  - DirichletBoundaryCondition
 *  - NeumannBoundaryCondition
 *  - RobinBoundaryCondition
 *
 * it is part of EquationEnsemble.
 */
class IrregularBoundaryConditionStrategy : public StateIndicator
{
public:

    virtual
    ~IrregularBoundaryConditionStrategy();

public:

    inline const std::string&
    get_variable_complete_symbol() const;

    /**
     * @return the boundary condition name.
     * @note that keep distinction between boundary condition name
     * and boundary name.
     * a boundary name refers to the boundary that can be imposed
     * any boundary condition.
     */
    inline const std::string&
    get_bc_name() const;

    inline const IrregularBoundaryConditionRange&
    get_act_range() const;

    inline const PDEEquationEnsembleStrategy*
    get_equation_ensemble() const;

    //act_range---------------
    inline void
    add_boundary_names(
            const std::set<std::string>& boundary_names);

    inline const std::set<std::string>&
    get_boundary_names() const;

    inline const std::string&
    get_range() const;

    inline void
    set_range(
            const std::string& range);
    //act_range---------------

public:
    //DIRICHLET  //ROBIN
#if 0
    virtual void
    set_para_fb(
            gFreeMAPs::ParaFluxBean* para_fb){ }

    virtual gFreeMAPs::ParaFluxBean*
    get_para_fb(){ }

    //ROBIN
    virtual void
    set_para_h(
            gFreeMAPs::ParaFluxBean* para_h){ }

    virtual gFreeMAPs::ParaFluxBean*
    get_para_h(){ }

    //HEAT_SOURCE
    virtual void
    set_para_source(
            gFreeMAPs::ParaFluxBean* para_source){ }

    virtual gFreeMAPs::ParaFluxBean*
    get_para_source(){ }

    //NEUMANN
    virtual void
    set_para_flux(
            gFreeMAPs::ParaFluxBean* para_flux){ }

    virtual gFreeMAPs::ParaFluxBean*
    get_para_flux(){ }
#endif

    //NEUMANN
    virtual void set_coef_absorption(
            const std::string& coef_absorption){ }

    virtual const std::string&
    get_coef_absorption(){ }

    //NEUMANN
    virtual void set_direction_type(
            const DirectionType& type){ }

    virtual const DirectionType&
    get_direction_type(){ }

    //NEUMANN
    virtual void set_direction(
            const double& x,
            const double& y,
            const double& z){ }

    virtual const double
    get_direction_x(){ }

    //NEUMANN
    virtual const double
    get_direction_y(){ }

    virtual const double
    get_direction_z(){ }
#if 0
    //PRESSURE
    virtual void
    set_para_pressure(
            gFreeMAPs::ParaFluxBean* para_pressure){ }

    virtual gFreeMAPs::ParaFluxBean*
    get_para_pressure(){ }
#endif
    virtual void set_para_init_temperature(
            const std::string& para_init_temperature){ }

    virtual const std::string&
    get_para_init_temperature(){ }

public:

    virtual void
    clear();

    /**
     * @return a concrete boundary condition by it's bc_type
     */
    static IrregularBoundaryConditionStrategy*
    create_object (
        const BoundaryConditionType bc_type,
        const std::string& parent_name,
        const std::string& bc_name,
        const PDEEquationEnsembleStrategy* equation_ensemble);

    /**
     * @return the boundary condition type
     */
    virtual BoundaryConditionType
    get_type() const = 0;

    virtual bool
    require_set_variable() const = 0;

   virtual  void
    get_from_input (
        const InputDatabase* db);

    friend std::ostream&
    operator << (
        std::ostream& os,
        const IrregularBoundaryConditionStrategy& rhs);

    virtual void
    get_info_for_derived_object_from_input (
        const InputDatabase* db) = 0;

    virtual std::string
    get_info_from_derived_object() const = 0;

protected:

    /*
     * constructor, be protected, so could not initialize it directly, must use in inherit
     */
    explicit
    IrregularBoundaryConditionStrategy (
            const std::string& parent_name,
            const std::string& bc_name,
            const PDEEquationEnsembleStrategy* equation_ensemble,
            bool is_registered_in_info_manager = false);

protected:

    typedef StateIndicator Parent;

    std::string d_bc_name;

    /*
     * the variables that this boundary work for.
     */
    std::string d_variable_complete_symbol;

    /*
     * boundary name is the reference to the boundary that this boundary condition act on.
     * one can access the boundary by it's name through BoundaryInfo.
     *
     * use d_is_boundary_name_set to tell whether the boundary name is set.
     * if not set, all the boundary in the region will be used.
     */
    IrregularBoundaryConditionRange d_act_range;

    const PDEEquationEnsembleStrategy* d_equation_ensemble;

private:

    DISALLOW_COPY_AND_ASSIGN (IrregularBoundaryConditionStrategy);
};

}

#include "COMMON/bdry/IrregularBoundaryConditionStrategy.inl"

#endif
